using System;
using System.Dynamic;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;

namespace Four
{
    public class Program
    {
        // 定义一个委托类型, 它兼容任何返回类型是 int 并有一个int 类型的参数的方法，比如下面的 Square
        delegate int Transformer(int x);

        static int Square(int x) => x * x;
        static int AddOne(int x) => x + 1;

        public static void Test1()
        {
            // 将方法赋值给委托变量就能创建一个委托实例
            Transformer t = Square;
            // 委托就类似于别名一样
            int answer = t(12);
            Console.WriteLine(answer); // 144
            Console.WriteLine(t.Method); // Int32 Square(Int32)
            t += AddOne;
            // 多播委托可以联结多个委托实例， t 先调用 Square 再调用 AddOne 并返回最后一个委托实例返回的值
            answer = t(12);
            Console.WriteLine(answer); // 13
            Console.WriteLine(t.Method); // Int32 AddOne(Int32)
        }

        // 声明委托
        public delegate void NumberChangedHandler(int oldNumber, int newNumber);

        public class FunnyNumber
        {
            private string symbol;
            private int number;

            public FunnyNumber(string symbol)
            {
                this.symbol = symbol;
            }

            // 声明事件，在委托成员前面加 event 关键字即可
            public event NumberChangedHandler NumberChanged;

            public int Number
            {
                get => number;
                set
                {
                    if (number == value)
                    {
                        // 数字无变化
                        return;
                    }

                    int oldNumber = number;
                    number = value;
                    if (NumberChanged != null)
                    {
                        // 所有委托的方法会被调用，这里实现了观察着模式
                        NumberChanged(oldNumber, number);
                    }
                }
            }
        }

        public class NumberChangedEventArgs : System.EventArgs
        {
            public readonly int LastNumber;
            public readonly int NewNumber;

            public NumberChangedEventArgs(int lastNumber, int newNumber)
            {
                LastNumber = lastNumber;
                NewNumber = newNumber;
            }
        }

        /**
         * 标准事件模式的委托必须以 void 为返回值；
         * 委托必须接受两个参数，object 类型的事件广播者 和 传递的信息；
         * 委托名称必须以 EventHandler 结尾。
         * 下面是源码
         */
        // public delegate void EventHandler<TEventArgs>(object source, TEventArgs e) where TEventArgs : EventArgs;
        public class FoodNumber
        {
            private string symbol;
            private int number;

            public FoodNumber(string symbol)
            {
                this.symbol = symbol;
            }

            public event EventHandler<NumberChangedEventArgs> NumberChanged;

            /**
             * 该模式需要编写一个 protected 的虚方法来触发事件，方法名是 On 加上事件名，并接受唯一参数 EventArgs
             */
            protected virtual void OnNumberChanged(NumberChangedEventArgs e)
            {
                NumberChanged?.Invoke(this, e);
            }

            public int Number
            {
                get => number;
                set
                {
                    if (number == value)
                    {
                        return;
                    }

                    int oldNumber = number;
                    number = value;
                    OnNumberChanged(new NumberChangedEventArgs(oldNumber, number));
                }
            }
        }

        public static void Test2()
        {
            FoodNumber foodNumber = new FoodNumber("Afra55");
            foodNumber.Number = 100;
            // 注册事件
            foodNumber.NumberChanged += food_NumberChanged;
            foodNumber.Number = 200;
            foodNumber.Number = 300;
            foodNumber.Number = 400;
        }

        static void food_NumberChanged(object sender, NumberChangedEventArgs e)
        {
            Console.WriteLine($"{e.LastNumber} -> {e.NewNumber}");
        }

        public static void Test3()
        {
            Transformer sqr = delegate(int i) { return i * i; };
            Console.WriteLine(sqr(12));
            Transformer sqrLambda = x => x * x;
            Console.WriteLine(sqrLambda(2));
        }


        public static void Test4()
        {
            Console.WriteLine("Afra55".isCapitalized()); // True
            Console.WriteLine("afra55".isCapitalized()); // False

            var person = new {Name = "Afra55", Age = 20};
            var person1 = new {Name = "Afra55", Age = 20};
            Console.WriteLine(person == person1); // False
            Console.WriteLine(person.Equals(person1)); // True
            Console.WriteLine(person.GetType() == person1.GetType()); // True

            // 元组元素可以简单的在括号中初始化值
            var user = ("Bfra55", 10);
            Console.WriteLine(user.Item1); // Bfra55
            Console.WriteLine(user.Item2); // 10

            // 元组是值类型，可以指定元组元素类型
            (string, long) u = ("Bfra55", 20);

            // 可以为元素定义名字
            var u1 = (Name: "Cfra55", Age: 22);
            Console.WriteLine(u1.Name);
            Console.WriteLine(u1.Age);

            (string Name, int Age) u2 = ("Dfra55", 22);
            Console.WriteLine(u2.Equals(u1)); // True
        }

        class User : DynamicObject
        {
            private int age;
            private string name;

            public int Age
            {
                get => age;
                set => age = value;
            }

            public string Name
            {
                get => name;
                set => name = value;
            }

            public void ShowInfo()
            {
                Console.WriteLine($"{Age}, {Name}");
            }

            public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
            {
                Console.WriteLine(binder.Name + " method was called");
                result = null;
                return true;
                // return base.TryInvokeMember(binder, args, out result);
            }
        }

        public static void Test5()
        {
            // 动态绑定
            dynamic d = new User();
            // 编译时并不知道 d 有 ShowInfo 方法，在运行时才会去查找这个方法
            d.Name = "Afra55";
            d.Age = 123;
            d.ShowInfo();
            d.WhatDoYouDo(); // WhatDoYouDo method was called
        }

        // 参数动态绑定，返回值也动态绑定，失去了类型安全的保护，可能发生运行时异常
        static dynamic Mean(dynamic x, dynamic y) => (x + y) / 2;

        public static void Test6()
        {
            int x = 3, y = 4;
            Console.WriteLine(Mean(x, y));
            Console.WriteLine(Mean(x, "22")); // .RuntimeBinderException
        }


        public struct Lover
        {
            int age;
            string name;

            public Lover(int age, string name)
            {
                this.age = age;
                this.name = name;
            }

            public static Lover operator +(Lover a, Lover b)
            {
                return new Lover(a.age + b.age, a.name + " and " + b.name);
            }

            public int Age
            {
                get => age;
                set => age = value;
            }

            public string Name
            {
                get => name;
                set => name = value;
            }
        }

        class FixTest
        {
            public int number = 0;
        }

        public static void Test7()
        {
            Lover A = new Lover(12, "Afra");
            Lover B = new Lover(32, "Bfra");
            Lover C = A + B;
            Console.WriteLine($"{C.Name} ~ {C.Age}"); // Afra and Bfra ~ 44

            FixTest fixTest = new FixTest();
            unsafe
            {
                fixed (int* p = &fixTest.number)
                {
                    *p = 9;
                }

                Console.WriteLine(fixTest.number); // 9
            }
        }

        unsafe struct UnsafeUnicodeString
        {
            public short Length;
            public fixed byte Buffer[30]; // 分配30字节缓冲区
        }

        public static void Test8()
        {
            unsafe
            {
                int* a = stackalloc int[10];
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine(a[i]);
                }
            }
        }
    }

    public static class StringHelper
    {
        public static bool isCapitalized(this string s)
        {
            if (string.IsNullOrEmpty(s)) return false;
            return char.IsUpper(s[0]);
        }
    }

#define DEBUG
    class DebugTest
    {
        void Test()
        {
#if DEBUG
            //根据DEBUG符号定义与否来有条件地对其中语句进行编译, 如果移除 #define DEBUG 就不会进行下面语句的编译
            Console.WriteLine("Debug");
#endif
        }
    }
}